package tcln.gxtx.client.utils.assertion;

import java.text.MessageFormat;
import java.util.Collection;

import tcln.gxtx.client.utils.collection.GwtCollectionUtils;
import tcln.gxtx.client.utils.lang.GwtStringUtils;

/**
 * An assert class for assertion.
 * 
 * @author Truong Chau Lien Ngoc (lienngoc@gmail.com)
 */
public final class GwtAssert {

    /**
     * Assert executor class for arguments. If one of the assertion methods of this object is not succeeded,
     * {@link IllegalArgumentException} will be thrown.
     */
    public static final AssertExecutor ARGUMENTS = new AbstractAssertExecutor() {
        @Override
        void throwRuntimeException(String message, Object... params) {
            throw new IllegalArgumentException(MessageFormat.format(message, params));
        }
    };

    /**
     * Assert executor class for states inside methods. If one of the assertion methods of this object is not succeeded,
     * {@link IllegalStateException} will be thrown.
     */
    public static final AssertExecutor STATE = new AbstractAssertExecutor() {
        @Override
        void throwRuntimeException(String message, Object... params) {
            throw new IllegalStateException(MessageFormat.format(message, params));
        }
    };

    /**
     * Default implementation for all assert executors. The only method subclasses have to implement is
     * {@link #throwRuntimeException(String, Object...)} which throws correct runtime exception.
     * 
     * @author Truong Chau Lien Ngoc (lienngoc@gmail.com)
     */
    private static abstract class AbstractAssertExecutor implements AssertExecutor {
        abstract void throwRuntimeException(String message, Object... params);

        /**
         * {@inheritDoc}
         */
        public void notNull(Object object, String message, Object... params) {
            if (object == null) {
                throwRuntimeException(message, params);
            }
        }

        /**
         * {@inheritDoc}
         */
        public void isTrue(boolean expression, String message, Object... params) {
            if (!expression) {
                throwRuntimeException(message, params);
            }
        }

        /**
         * {@inheritDoc}
         */
        public void isFalse(boolean expression, String message, Object... params) {
            isTrue(!expression, message, params);
        }

        /**
         * {@inheritDoc}
         */
        public void notEmpty(String object, String message, Object... params) {
            if (GwtStringUtils.isEmpty(object)) {
                throwRuntimeException(message, params);
            }
        }

        /**
         * {@inheritDoc}
         */
        public void notEmpty(Collection<?> coll, String message, Object... params) {
            if (GwtCollectionUtils.isEmpty(coll)) {
                throwRuntimeException(message, params);
            }
        }

        /**
         * {@inheritDoc}
         */
        public void fail(String message, Object... params) {
            throwRuntimeException(message, params);
        }
    }

    /**
     * @author Truong Chau Lien Ngoc (lienngoc@gmail.com)
     */
    public interface AssertExecutor {

        /**
         * Checks if given expression is <code>true</code> or not.
         * 
         * @param expression
         *            Expression to check.
         * @param message
         *            Message to show if given expression is NOT <code>true</code>.
         * @param params
         *            Message parameters.
         */
        void isTrue(boolean expression, String message, Object... params);

        /**
         * Checks if given expression is <code>false</code> or not.
         * 
         * @param expression
         *            Expression to check.
         * @param message
         *            Message to show if given expression is NOT <code>false</code>.
         * @param params
         *            Message parameters.
         */
        void isFalse(boolean expression, String message, Object... params);

        /**
         * Checks if given object is NOT <code>null</code>.
         * 
         * @param object
         *            Object to check.
         * @param message
         *            Message to show if given object is <code>null</code>.
         * @param params
         *            Message parameters.
         */
        void notNull(Object object, String message, Object... params);

        /**
         * Checks if given string is NOT empty (blanks are considered NOT empty).
         * 
         * @param object
         *            Object to check.
         * @param message
         *            Message to show if given string is empty.
         * @param params
         *            Message parameters.
         */
        void notEmpty(String object, String message, Object... params);

        /**
         * Checks if given collection is NOT empty (<code>null</code> considered empty).
         * 
         * @param object
         *            Object to check.
         * @param message
         *            Message to show if given collection is <code>null</code> or empty.
         * @param params
         *            Message parameters.
         */
        void notEmpty(Collection<?> object, String message, Object... params);

        /**
         * Surely throws a runtime exception. This method is useful for the cases when the code below this line would be
         * sure a mistake.
         * 
         * @param message
         *            Message to show if given string is empty.
         * @param params
         *            Message parameters.
         */
        void fail(String message, Object... params);
    }
}
